﻿#region Legal

// Jimmy Zimmerman
// Team Mongoose
//
// END USER LICENSE AGREEMENT
// IMPORTANT - READ THIS CAREFULLY:  This End User License Agreement is a legal agreement
// between you (either an individual, business entity, currently active identity of an
// individual with Multiple Personality Disorder, octopus overlord, or otherworldly entity),
// and Team Mongoose, for the enclosed, components.
//
// By reading this document and/or installing this product, you agree to be bound by the
// terms of this EULA.
//
// Team Mongoose owns all copyright, trade secret, trademark, trade wars,
// patent, portent, and potential rights to these components.  Team Mongoose
// grants you the right to deploy the enclosed components.
//
// If you agree to the terms of this EULA, a license to use these components is granted to you.
//
// If you should happen to benefit from the enclosed components, then you are legally and
// contractually bound to thank us for it. Send your regards to jimmyzimms@hotmail.com.
//
// OTHER RIGHTS AND LIMITATONS
// You may not reverse-engineer, decompile, decode, disassemble, psycho-analyze, or otherwise
// attempt to find hidden meanings between the lines of this EULA; unless, of course, you should
// happen to find some, and they are funny.
//
// You may not translate this EULA or any part of the components into Ancient Sumerian.
//
// THESE COMPONENTS ARE PROVIDED “AS-IS” WITHOUT WARRANTY OF ANY KIND. ANY USE OF THE COMPONENTS
// CONTAINED IS AT YOUR OWN RISK. TEAM MONGOOSE DISCLAIM ALL WARRANTIES, EITHER
// EXPRESS OR IMPLIED, WITH RESPECT TO THE ACCURRACY AND CORRECTNESS OF THE COMPONENTS CONTAINED
// HEREIN. TEAM MONGOOSE DOES NOT WARRANT THAT THE COMPONENTS ARE FLAWLESS.
//
// REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS, WITH OR WITHOUT MODIFICATION, ARE PERMITTED
// PROVIDED THAT THE FOLLOWING CONDITIONS ARE MET:
// * REDISTRIBUTIONS OF SOURCE CODE MUST RETAIN THE ABOVE COPYRIGHT NOTICE
// * REDISTRIBUTIONS IN BINARY FORM MUST NOTE THE USE OF THE COMPONENT IN DOCUMENTATION AND/OR
//   OTHER MATERIALS PROVIDED WITH THE DISTRIBUTION.
// * NEITHER THE NAME OF TEAM MONGOOSE MAY BE USED TO ENDORES OR PROMOTE PRODUCTS
//   DERIVED FROM THIS SOFTWARE WITHOUT SPECIFIC PRIOR WRITTEN PERMISSION.
//
// IN NO EVENT SHALL TEAM MONGOOSE BE HELD LIABLE FOR INCIDENTAL, SPECIAL, INDIRECT,
// INCONSEQUENTIAL, UNBELIEVABLE, EXAGGERATED, VERBOSE, OR TYPICAL DAMAGES INCURRED WHILE USING
// THE ENCLOSED COMPONENTS.
//
// OUR STUFF ALWAYS WORKS - SOMETIMES.

#endregion

using System;
using System.Diagnostics.Contracts;

namespace DiceRoller.Dice
{
    /// <summary>
    /// Abstract representation of all dice concepts. A die instance represents a real life counterpart
    /// in use and function for selection of a randomly generated value in a certain range. Dice should
    /// be able to be represented as a composite or singly as is needed.
    /// </summary>
    [ContractClass(typeof(DieContracts))]
    public abstract class Die
    {
        #region Fields
        
        private readonly Int32 minValue;
        private readonly Int32 maxValue;
        private readonly static Random DefaultRandomValueGenerator = new Random( DateTime.Now.Millisecond );

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Die"/> class with the indicated <see cref="MaximumValue"/> setting and leveraging the default minimum value of 1.
        /// </summary>
        /// <param name="maxValue">The maximum value the die can select. This is any value greater than 1.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxValue"/> is less than or equal to 1.</exception>
        protected Die(Int32 maxValue) : this(1, maxValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Die"/> class with the indicated <see cref="MinimumValue"/> and <see cref="MaximumValue"/> settings.
        /// </summary>
        /// <param name="minValue">The minimum value the die can select. This is usually 1.</param>
        /// <param name="maxValue">The maximum value the die can select. This is any value greater than <paramref name="minValue"/>.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <para><paramref name="minValue"/> is less than 1</para>
        /// <para>-OR-</para>
        /// <para><paramref name="minValue"/> is less than or equal to <paramref name="maxValue"/></para>
        /// </exception>
        protected Die(Int32 minValue, Int32 maxValue)
        {
            if (minValue < 1) throw new ArgumentOutOfRangeException("minValue", String.Format(null, "The minimum value '{0}' must be greater than zero.", minValue));
            if (minValue >= maxValue) throw new ArgumentOutOfRangeException("minValue", String.Format(null, "The minimum value of '{0}' must be less than the supplied maximum value of '{1}'", minValue, maxValue));

            this.minValue = minValue;
            this.maxValue = maxValue;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the minimum value the dice can select when rolled. This is always at least 1.
        /// </summary>
        /// <value>The minimum value the dice can select when rolled.</value>
        public virtual Int32 MinimumValue
        {
            get
            {
                //Contract.Ensures(Contract.Result<Int32>() > 0);

                return this.minValue;
            }
        }

        /// <summary>
        /// Gets the maximum value the dice can select when rolled. This is always greater than <see cref="MinimumValue"/>.
        /// </summary>
        /// <value>The maximum value the dice can select when rolled.</value>
        public virtual Int32 MaximumValue
        {
            get
            {
                //Contract.Ensures(Contract.Result<Int32>() > this.MinimumValue);

                return this.maxValue;
            }
        }

        /// <summary>
        /// Gets the <see cref="Random"/> number generator for the current instance. This value is not required to be unique across instances.
        /// </summary>
        /// <remarks>The <see cref="Random"/> number generator for the current instance</remarks>
        protected virtual Random RandomGenerator
        {
            get
            {
                //Contract.Ensures(Contract.Result<Random>() != null);

                return DefaultRandomValueGenerator;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Rolls the current <see cref="Die"/> instance and returns the result.
        /// </summary>
        /// <returns>The result of the random roll.</returns>
        public abstract Int32 Roll();

        #endregion
    }

    [ContractClassFor(typeof(Die))]
    internal abstract class DieContracts : Die
    {
        protected DieContracts() : base(1, 2)
        {
        }

        public override Int32 Roll()
        {
            //Contract.Ensures(Contract.Result<Int32>() <= this.MaximumValue);

            return default(Int32);
        }
    }
}
